#!/usr/bin/ruby -w

require "test/unit"
require "cake.rb"

# Both Joe and Jill should both aim for the best possible outcome no matter
# how dumb or smart the other person is. Therefore, the idea is to test one
# person's behavior separately by simulating the other person.
class TestCake < Test::Unit::TestCase

  # Joe should always get 1.0 cake or more since he has the advantage of cutting
  # the cake twice.
  def test_joe
    # Jill always chooses the first cake
    ask_joe(Cake.new(0.9), true, 1.0)
    ask_joe(Cake.new(0.8), true, 1.1)
    ask_joe(Cake.new(0.7), true, 1.2)
    ask_joe(Cake.new(0.6), true, 1.3)
    ask_joe(Cake.new(0.5), true, 1.4)
    ask_joe(Cake.new(0.4), true, 1.3)
    ask_joe(Cake.new(0.3), true, 1.2)
    ask_joe(Cake.new(0.2), true, 1.1)
    ask_joe(Cake.new(0.1), true, 1.0)

    # Jill always chooses the second cake
    ask_joe(Cake.new(0.9), false, 1.4)
    ask_joe(Cake.new(0.8), false, 1.3)
    ask_joe(Cake.new(0.7), false, 1.2)
    ask_joe(Cake.new(0.6), false, 1.1)
    ask_joe(Cake.new(0.5), false, 1.0)
    ask_joe(Cake.new(0.4), false, 1.1)
    ask_joe(Cake.new(0.3), false, 1.2)
    ask_joe(Cake.new(0.2), false, 1.3)
    ask_joe(Cake.new(0.1), false, 1.4)
  end

  # Joe has an advantage because he can cut as well as choose a piece from one
  # cake. So, we assume that the best possible outcome for Jill is to get 1.0
  # cake, and we aim to get as close to that as possible.
  #
  # In this the table is shown what the best possible outcome for Jill is:
  # 
  # Biggest in 1st cake    Pick 1st cake      Pick 2nd cake
  # 0.9                    0.9 + 0.1 = 1.0    0.1 + 0.5 = 0.6
  # 0.8                    0.8 + 0.1 = 0.9    0.2 + 0.5 = 0.7
  # 0.7                    0.7 + 0.1 = 0.8    0.3 + 0.5 = 0.8
  # 0.6                    0.6 + 0.1 = 0.7    0.4 + 0.5 = 0.9
  #
  # If Jill does not pick the first cake, we can expect Joe will make a cut of
  # 0.5/0.5 for the second cake. In that case, 0.7 is the turning point. Below
  # that it is no longer beneficial for Jill to pick the first cake.
  def test_jill
    jill = Jill.new()
    assert_equal(true, jill.pick_cake?(Cake.new(0.9)))
    assert_equal(true, jill.pick_cake?(Cake.new(0.8)))
    assert_equal(true, jill.pick_cake?(Cake.new(0.7)))
    assert_equal(false, jill.pick_cake?(Cake.new(0.6)))
    assert_equal(false, jill.pick_cake?(Cake.new(0.5)))
    assert_equal(false, jill.pick_cake?(Cake.new(0.4)))
    assert_equal(true, jill.pick_cake?(Cake.new(0.3)))
    assert_equal(true, jill.pick_cake?(Cake.new(0.2)))
    assert_equal(true, jill.pick_cake?(Cake.new(0.1)))
  end

  private

  def ask_joe(first_cake, jills_choice, expected)
    joe = Joe.new()
    second_cake = joe.cut_second_cake(first_cake, jills_choice)
    assert_in_delta(expected, joe.my_cake_amount(first_cake, second_cake,
                                                 jills_choice), 0.05)
  end

end

# Indication of time spent: 3 hours
